package com.vend.common.db;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

import androidx.annotation.NonNull;

import org.greenrobot.greendao.query.QueryBuilder;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 对数据库的表进行CRUD
 * Created by jiadong on 2016/11/7.
 */

public class DBManager {

    private static volatile DBManager sDBManager;
    private GreenDAOHelper mGreenDAOHelper;
    Context mContext;

    private DBManager(Context context) {
        mContext = context;
        mGreenDAOHelper = GreenDAOHelper.getInstance();
        mGreenDAOHelper.init(context, DBConfig.DB_NAME);
    }

    private DBManager() {

    }

    public GreenDAOHelper getmGreenDAOHelper() {
        return mGreenDAOHelper;
    }

    public void setmGreenDAOHelper(GreenDAOHelper mGreenDAOHelper) {
        this.mGreenDAOHelper = mGreenDAOHelper;
    }

    /**
     * 初始化方法在Application里面调用,请不要在其他方法里面调用
     *
     * @param c
     */
    public synchronized static void init(Context c) {
        Log.e("tag","初始GreenDao");
        synchronized (DBManager.class) {
            if (sDBManager == null) {
                sDBManager = new DBManager(c.getApplicationContext());
            }
        }
    }

    /**
     * 获取数据库操作实例
     *
     * @return
     */
    public static DBManager getInstances() {
        return sDBManager != null ? sDBManager : new DBManager();
    }

    /**
     * 完成对数据库中表的插入
     *
     * @param t
     * @return
     */
    public <T> boolean insert(T t) {
        if (mGreenDAOHelper == null) return false;
        boolean flag = false;
        try {
            flag = mGreenDAOHelper.getDaoSession().insert(t) != -1;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 插入多条记录，开启新的线程
     *
     * @param list
     * @return
     */
    public <T> boolean insertList(final List<T> list) {
        if (mGreenDAOHelper == null) return false;
        boolean flag = false;
        try {
            mGreenDAOHelper.getDaoSession().runInTx(new Runnable() {
                @Override
                public void run() {
                    for (T t : list) {
                        mGreenDAOHelper.getDaoSession().insertOrReplace(t);
                    }

                }
            });

            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    public <T> boolean insertListTx(@NonNull List<T> list) {
        Log.d("DBManager", "list.size="+list.size());
        if (mGreenDAOHelper == null) {return false;}
        boolean flag = false;
        try {
            mGreenDAOHelper.getDaoSession().getDao(list.get(0).getClass()).insertInTx((ArrayList)list);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }


    /**
     * 批量更新列表
     *
     * @param list
     * @return
     */
    public <T> boolean updateList(final List<T> list) {
        if (mGreenDAOHelper == null) return false;
        boolean flag = false;
        try {
            mGreenDAOHelper.getDaoSession().runInTx(new Runnable() {
                @Override
                public void run() {
                    for (T t : list) {
                        mGreenDAOHelper.getDaoSession().update(t);
                    }
                }
            });
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }


    /**
     * 批量删除
     *
     * @param list
     * @return
     */
    public <T> boolean deleteList(final List<T> list) {
        if (mGreenDAOHelper == null) return false;
        boolean flag = false;
        try {
            mGreenDAOHelper.getDaoSession().runInTx(() -> {
                for (T t : list) {
                    mGreenDAOHelper.getDaoSession().delete(t);
                }
            });
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 完成某一条记录的修改
     *
     * @param t
     * @return
     */
    public <T> boolean update(T t) {
        if (mGreenDAOHelper == null) return false;
        boolean flag = false;
        try {
            mGreenDAOHelper.getDaoSession().update(t);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 删除单条数据(按照指定的id进行删除 delete from user where _id = ?)
     *
     * @param t
     * @return
     */
    public <T> boolean delete(T t) {
        if (mGreenDAOHelper == null) return false;
        boolean flag = false;
        try {
            mGreenDAOHelper.getDaoSession().delete(t);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 删除表的所有数据
     *
     * @param cls
     */
    public boolean deleteAll(Class cls) {
        if (mGreenDAOHelper == null) return false;
        boolean flag = false;
        try {
            mGreenDAOHelper.getDaoSession().deleteAll(cls);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }


    /**
     * 返回表的所有数据
     *
     * @param cls
     * @return
     */
    public <T> List<T> getAll(Class cls) {
        if (mGreenDAOHelper == null) return null;
        try {
            return mGreenDAOHelper.getDaoSession().loadAll(cls);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 按照主键返回单行数据
     *
     * @param cls
     * @param id
     * @return
     */
    public <T> T getOne(Class cls, long id) {
        if (mGreenDAOHelper == null) return null;

        T t = null;
        try {
            t = (T) mGreenDAOHelper.getDaoSession().load(cls, id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     * 使用native sql进行查询
     *
     * @param cls
     * @param sql
     * @param selectionArgs
     * @return
     */
    public <T> List<T> queryBySQL(Class cls, String sql, String[] selectionArgs) {
        if (mGreenDAOHelper == null) return null;
        List<T> list = null;
        try {
            list = mGreenDAOHelper.getDaoSession().queryRaw(cls, sql, selectionArgs);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 使用查询构建器进行查询
     * <p>
     * * select  * from user where name like ? or age =? ...
     * >  <  <=  >=  !=  in  between  and  limit ...
     *
     * @param builder
     * @param <T>
     * @return
     */
    public <T> List<T> queryByBuilder(QueryBuilder<T> builder) {
        if (mGreenDAOHelper == null) return null;
        List<T> list = null;
        try {
            list = builder.list();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }


    /**
     * 使用构造器查询分页
     *
     * @param builder
     * @param offset
     * @param limit
     * @param <T>
     * @return
     */
    public <T> List<T> queryByBuilder(QueryBuilder<T> builder,int offset, int limit){
        if(mGreenDAOHelper == null) {return null;}
        List<T> list = null;
        try {
            list = builder.offset(offset).limit(limit).list();
        } catch (Exception e){
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 关闭所有的操作,数据库开启的时候，使用完毕了必须要关闭
     */
    public void closeConnection() {
        if (mGreenDAOHelper != null) {
            mGreenDAOHelper.closeConnection();
        }
    }


    public static boolean copyDatabase(Context mContext) {
        File oldDBFile = mContext.getDatabasePath(DBConfig.DB_NAME);
        String rootFilePath = Environment.getExternalStoragePublicDirectory("").getPath();
        String newPath = rootFilePath + File.separator + "ydjc" + File.separator + DBConfig.DB_NAME;
        File dbFile = new File(newPath);

        boolean isFileThere = false;
        if (!dbFile.exists()) {
            isFileThere = false;
        } else
            isFileThere = true;

        //文件不存在进行复制
        if (!isFileThere) {
            try {
                isFileThere =  customBufferBufferedStreamCopy(oldDBFile, new File(newPath));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return isFileThere;

    }

    public static boolean isNewDatabaseThere() {
        String rootFilePath = Environment.getExternalStoragePublicDirectory("").getPath();
        String newPath = rootFilePath + File.separator + "ydjc" + File.separator + DBConfig.DB_NAME;
        File dbFile = new File(newPath);

        boolean isFileThere = false;
        if (!dbFile.exists()) {
            isFileThere = false;
        } else
            isFileThere = true;
        return isFileThere;
    }

    private static boolean customBufferBufferedStreamCopy(File source, File target) throws IOException {
        boolean result = false;
        InputStream fis = null;
        OutputStream fos = null;
        try {
            fis = new BufferedInputStream(new FileInputStream(source));
            fos = new BufferedOutputStream(new FileOutputStream(target));
            byte[] buf = new byte[4096];
            int i;
            while ((i = fis.read(buf)) != -1) {
                fos.write(buf, 0, i);
            }
            result = true;
        }
        catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) fis.close();
            if (fos != null) fos.close();
        }
        return result;
    }

    public interface Callback{
        void finishCopyNotice();
    }
}
